﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.CodeDom;
using System.CodeDom.Compiler;

namespace ParseXAML.CodeDOM
{
    internal class PartialResource
    {
        protected CodeDomProvider DomProvider;

        protected Global global;

        protected string extension;

        protected bool isDirectoryAsNamespace;

        internal PartialResource(Global global, string extension)
        {
            this.global = global;
            this.extension = extension;
            this.isDirectoryAsNamespace = IsDirectoryAsNamespace(extension);
        }

        public static bool IsDirectoryAsNamespace( string extension )
        {
            return (extension.ToLowerInvariant() != ".vb");
        }

        public static bool CanGenerateCode(string extension)
        {
            return CodeDomProvider.IsDefinedExtension(extension);
        }

        public static string GetResXClassName(string resXClassName)
        {
            return string.Concat(resXClassName, "Local");
        }

        internal StringBuilder GenCode(string className, string namespaceClass, string resXClassName, string resXnamespace, string resourceName, string resourceFileName)
        {
            CodeNamespace codeNamespace = this.CreateNamespace(namespaceClass);
            codeNamespace.Imports.Add(new CodeNamespaceImport("System"));

            codeNamespace.Comments.Add(new CodeCommentStatement("------------------------------------------------------------------------------"));
            codeNamespace.Comments.Add(new CodeCommentStatement("<auto-generated>"));
            codeNamespace.Comments.Add(new CodeCommentStatement("Generated by XAML Localize (http://xamllocalize.codeplex.com)"));
            codeNamespace.Comments.Add(new CodeCommentStatement("</auto-generated>"));
            codeNamespace.Comments.Add(new CodeCommentStatement("------------------------------------------------------------------------------"));

            CodeTypeDeclaration codeClass = new CodeTypeDeclaration(resXClassName);
//            codeClass.BaseTypes.Add(new CodeTypeReference(string.Concat(resXnamespace, ".", resXClassName)));

            CodeConstructor codeConstructor = new CodeConstructor();
            codeConstructor.Attributes = MemberAttributes.Public;

            codeClass.Members.Add(codeConstructor);

            codeNamespace.Types.Add(codeClass);

            AddResourceManager(codeClass, resXClassName, namespaceClass, resourceName);
            using (System.IO.Stream inputStream = System.IO.File.OpenRead(resourceFileName))
            {
                System.Xml.XPath.XPathDocument doc = new System.Xml.XPath.XPathDocument(inputStream);
                System.Xml.XPath.XPathNodeIterator it = doc.CreateNavigator().Select("//data");
                while (it.MoveNext())
                {
                    if (it.Current.GetAttribute("type", String.Empty).Length != 0)
                    {
                        continue; // Only interested in string resources
                    }

                    string key = it.Current.GetAttribute("name", String.Empty);
                    this.AddResourceMember(codeClass, key);
                }
            }

            return GenOutput(codeNamespace);
        }

        internal StringBuilder GenCode2(string className, string namespaceClass, List<TranslatLine> translatLines, string resourceName)
        {
            CodeNamespace codeNamespace = this.CreateNamespace(namespaceClass);
            codeNamespace.Imports.Add(new CodeNamespaceImport("System"));

            codeNamespace.Comments.Add(new CodeCommentStatement("------------------------------------------------------------------------------"));
            codeNamespace.Comments.Add(new CodeCommentStatement("<auto-generated>"));
            codeNamespace.Comments.Add(new CodeCommentStatement("Generated by XAML Localize (http://xamllocalize.codeplex.com)"));
            codeNamespace.Comments.Add(new CodeCommentStatement("</auto-generated>"));
            codeNamespace.Comments.Add(new CodeCommentStatement("------------------------------------------------------------------------------"));

            CodeTypeDeclaration codeClass = new CodeTypeDeclaration(className);
            codeClass.IsPartial = true;

            codeNamespace.Types.Add(codeClass);

            this.AddResourceManager(codeClass, className, namespaceClass, resourceName);

            CodeMemberMethod codeMember = new CodeMemberMethod();
            codeMember.Attributes = MemberAttributes.Family | MemberAttributes.Final;
            codeMember.Name = "Translate";

            foreach (var o in translatLines)
            {
                this.AddTranslateMember(codeMember, o);
            }

            codeClass.Members.Add(codeMember);

            return GenOutput(codeNamespace);
        }

        protected CodeNamespace CreateNamespace(string namespaceClass)
        {
            // by default, VB has a default namespace
            if (!string.IsNullOrEmpty(this.global.DefaultNamespace))
            {
                if (!this.isDirectoryAsNamespace)
                {
                    if (namespaceClass.StartsWith(this.global.DefaultNamespace))
                        namespaceClass = namespaceClass.Substring(this.global.DefaultNamespace.Length);
                }
            }
            return new CodeNamespace(namespaceClass);
        }

        protected void AddTranslateMember(CodeMemberMethod codeMember, TranslatLine line)
        {
             //string.Format("this.{0}.{1} = ResourceManager.GetString(\"{2}\");", nameThis, l, resName));
             codeMember.Statements.Add( new CodeAssignStatement(
                 new CodePropertyReferenceExpression( new CodePropertyReferenceExpression( new CodeThisReferenceExpression(), line.Member ), line.Property ),
                 new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("resourceManager"), "GetString",
                    new CodePrimitiveExpression( line.Value ) ) ) );
        }

        protected StringBuilder GenOutput(CodeNamespace codeNamespace)
        {
            string language = CodeDomProvider.GetLanguageFromExtension(this.extension);
            DomProvider = CodeDomProvider.CreateProvider(language);

            CodeGeneratorOptions options = new CodeGeneratorOptions();
            options.IndentString = new string(' ', 3);

            StringBuilder sb = new StringBuilder();
            System.IO.StringWriter sw = new System.IO.StringWriter(sb);
            DomProvider.GenerateCodeFromNamespace(codeNamespace, sw, options);

            return sb;
        }

        protected void AddResourceManager(CodeTypeDeclaration codeClass, string resXClassName, string resXnamespace, string resourceName)
        {
            CodeMemberField fResourceManager = new CodeMemberField(typeof(System.Resources.ResourceManager), "resourceManager");
            fResourceManager.Attributes = MemberAttributes.Static | MemberAttributes.Private;
            fResourceManager.InitExpression = new CodeObjectCreateExpression(typeof(System.Resources.ResourceManager),
                new CodePrimitiveExpression(resourceName),
                new CodePropertyReferenceExpression(
                    new CodeTypeOfExpression(resXClassName), "Assembly"));
            codeClass.Members.Add(fResourceManager);
        }

        protected void AddResourceMember(CodeTypeDeclaration codeClass, string name)
        {
            CodeMemberProperty pGetString = new CodeMemberProperty();
            pGetString.Name = name;
            pGetString.Attributes = MemberAttributes.Static | MemberAttributes.Public;
            pGetString.Type = new CodeTypeReference(typeof(string));

            pGetString.GetStatements.Add(
                new CodeMethodReturnStatement(
                new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("resourceManager"), "GetString",
                    new CodePrimitiveExpression( name ) ) ) );

            codeClass.Members.Add(pGetString);
        }


    }
}
